﻿#if NETFX || NETCORE

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Apewer.Surface
{

    /// <summary>
    /// 
    /// </summary>
    public partial class BlockText : BaseControl
    {

        private const string modeinput = "input";
        private const string moderadio = "radio";
        private const string modecombo = "combo";

        // private bool _lonely = false;
        private bool _delemiter = false;
        private bool _statehover = false, _statefocus = false;
        private bool _busy = false;
        private string _mode = modeinput;

        // private Panel _body = new Panel();
        private Panel _left = new Panel();
        // private Panel _middle = new Panel();
        private Panel _right = new Panel();
        private BlockLabel _label = new BlockLabel();

        private TextBox _input = new TextBox();
        private ComboBox _combo = new ComboBox();

        private int _radiowidth = 80;
        private List<BlockButton> _radio = new List<BlockButton>();

        private List<string> _value = new List<string>();
        private List<string> _alias = new List<string>();
        private List<Color> _color = new List<Color>();
        private string _text = "";

        #region this

        /// <summary></summary>
        private void VarInit()
        {
            _label.Text = "Caption";
            _input.Text = Name;
        }

        /// <summary></summary>
        public BlockText()
        {
            this.Size = new Size(300, 40);

            VarInit();

            ControlInit();
            ControlAdjust();
            EventInit();
            GoColor();

            GoInput();
        }

        /// <summary></summary>
        public new void Dispose()
        {
            if (_left != null) _left.Dispose();
            if (_right != null) _right.Dispose();
            if (_label != null) _label.Dispose();
            if (_input != null) _input.Dispose();
            base.Dispose();
        }

        #endregion

        #region surface

        /// <summary></summary>
        private void ControlInit()
        {
            this.Controls.Add(_left);
            this.Controls.Add(_right);
            _left.Controls.Add(_label);
            _right.Controls.Add(_input);
            _right.Controls.Add(_combo);

            this.Padding = new Padding(1);

            _left.Dock = DockStyle.Left;
            _left.Padding = new Padding(8, 0, 8, 0);
            _left.Width = 100;

            _label.Dock = DockStyle.Fill;
            _label.TextAlign = ContentAlignment.MiddleCenter;

            _right.Dock = DockStyle.Right;

            _input.BorderStyle = BorderStyle.None;
            _input.Font = FormsUtility.DefaultFont;

            _combo.TabStop = false;
            _combo.FlatStyle = FlatStyle.Flat;
            _combo.Dock = DockStyle.Right;
            _combo.ItemHeight = Height - 8;
            _combo.MaxDropDownItems = 10;
            _combo.DrawMode = DrawMode.OwnerDrawVariable;
            _combo.DropDownStyle = ComboBoxStyle.DropDownList;
        }

        /// <summary></summary>
        private void ControlAdjust()
        {
            if ((this.Width > 0) && (this.Height > 0))
            {
                var vfontoffset = FormsUtility.MsyhExist ? 0 : 2;
                //var vshowcombo = (_combo.Items.Count > 0);

                _right.Width = Width - Padding.Left - Padding.Right - _left.Width - (_delemiter ? 1 : 0);

                switch (_mode)
                {
                    case modeinput:
                        _input.Height = 14;
                        _input.Width = _right.Width - 18;
                        _input.Left = 12;
                        _input.Top = (_right.Height - 14) / 2 - 1 + vfontoffset;
                        break;
                    case moderadio:
                        for (int i = 0; i < _radio.Count; i++)
                        {
                            _radio[i].Left = RadioWidth * i;
                            _radio[i].Top = 3;
                            _radio[i].Width = RadioWidth;
                            _radio[i].Height = this.Height - 8;
                        }
                        break;
                    case modecombo:
                        _combo.Width = _right.Width;
                        break;
                }
            }
        }

        /// <summary></summary>
        private void GoColor()
        {
            if (_statefocus)
            {
                this.BackColor = _focusborder;
                _left.BackColor = _focusleft;
                _left.ForeColor = _focuscaption;
                _right.BackColor = _focusright;
                _label.ForeColor = _focuscaption;
                _input.ForeColor = Locked ? _label.ForeColor : _focustext;
                // _middle.BackColor = _left.BackColor; // this.BackColor;
            }
            else
            {
                if (_statehover)
                {
                    this.BackColor = _hoverborder;
                    _left.BackColor = _hoverleft;
                    _left.ForeColor = _hovercaption;
                    _right.BackColor = _hoverright;
                    _label.ForeColor = _hovercaption;
                    _input.ForeColor = Locked ? _label.ForeColor : _hovertext;
                    // _middle.BackColor = _left.BackColor;
                }
                else
                {
                    this.BackColor = _normalborder;
                    _left.BackColor = _normalleft;
                    _left.ForeColor = _normalcaption;
                    _right.BackColor = _normalright;
                    _label.ForeColor = _normalcaption;
                    _input.ForeColor = Locked ? _label.ForeColor : _normaltext;
                    // _middle.BackColor = _left.BackColor;
                }
            }
            _input.BackColor = _right.BackColor;
        }

        /// <summary>设置样式为候选项。</summary>
        private void GoCandidate(BlockButton button)
        {
            button.NormalBorder = FormsUtility.White;
            button.NormalText = FormsUtility.GraceSilver;
            button.HoverBorder = FormsUtility.GraceWall;
            button.HoverText = FormsUtility.Gray;
        }

        /// <summary>设置样式为当前项。</summary>
        private void GoCurrent(BlockButton button)
        {
            button.NormalBorder = FormsUtility.GraceSilver;
            button.NormalText = Color.Black;
            button.HoverBorder = FormsUtility.GraceSilver;
            button.HoverText = Color.Black;
        }

        #endregion

        #region accessor

        /// <summary></summary>
        public event EventHandler Changed;

        /// <summary></summary>
        public bool Busy { get { return _busy; } private set { _busy = false; } }

        /// <summary></summary>
        public int RadioWidth
        {
            get { return _radiowidth; }
            set { _radiowidth = (value >= 0) ? value : 0; }
        }

        /// <summary>添加选项。</summary>
        /// <param name="value">选项值。</param>
        public void Add(string value)
        {
            Add(value, value, Color.Black);
        }

        /// <summary>添加选项。</summary>
        /// <param name="value">选项值。</param>
        /// <param name="color">文字颜色。</param>
        private void Add(string value, Color color)
        {
            Add(value, value, color);
        }

        /// <summary>添加选项。</summary>
        /// <param name="value">选项值。</param>
        /// <param name="alias">显示名称。</param>
        public void Add(string value, string alias)
        {
            Add(value, alias, Color.Black);
        }

        /// <summary>添加选项。</summary>
        /// <param name="value">选项值。</param>
        /// <param name="alias">显示名称。</param>
        /// <param name="color">文字颜色。</param>
        private void Add(string value, string alias, Color color)
        {
            if (value != null)
            {
                var v = string.IsNullOrEmpty(value) ? "" : value;
                var a = string.IsNullOrEmpty(alias) ? v : alias;
                var c = (color == null) ? Color.Black : color;
                _value.Add(v);
                _alias.Add(a);
                _color.Add(c);

                // combo
                _combo.Items.Add(a);

                // radio
                _radio.Add(new BlockButton());
                var index = _alias.Count - 1;
                _radio[index].Caption = _alias[index];
                _radio[index].Tag = value;
                _radio[index].BodyMargin = new Padding(1);
                _radio[index].MouseDown += Event_Radio_MouseDown;
                _radio[index].MouseMove += Event_Caption_MouseMove;
                _radio[index].MouseLeave += Event_Caption_MouseLeave;
                if (_mode != moderadio) _radio[index].Visible = false;
                _right.Controls.Add(_radio[index]);
                GoCandidate(_radio[index]);

                ControlAdjust();
            }
        }

        /// <summary>清除所有选项。</summary>
        public void Clean()
        {
            Clear();
        }

        /// <summary>清除所有选项。</summary>
        public void Clear()
        {
            _value.Clear();
            _alias.Clear();
            _color.Clear();
            _combo.Items.Clear();
            ControlAdjust();
        }

        /// <summary>切换到单选模式。</summary>
        public void GoRadio()
        {
            if (_mode == modeinput) _text = _input.Text;
            _mode = moderadio;

            _input.Visible = false;
            _combo.Visible = false;
            foreach (var vi in _radio) vi.Visible = true;

            ControlAdjust();
        }

        /// <summary>切换到输入模式。</summary>
        public void GoInput()
        {
            _input.Visible = true;
            _combo.Visible = false;
            foreach (var vi in _radio) vi.Visible = false;

            if (_mode != modeinput) _input.Text = _text;
            _mode = modeinput;

            ControlAdjust();
        }

        /// <summary>切换到下拉选择模式。</summary>
        public void GoCombo()
        {
            if (_mode == modeinput) _text = _input.Text;
            _mode = modecombo;

            _input.Visible = false;
            _combo.Visible = true;
            foreach (var vi in _radio) vi.Visible = false;

            ControlAdjust();
        }

        /// <summary>可选项中包含指定值。</summary>
        public bool Contain(string value)
        {
            foreach (var vi in _value)
            {
                if (vi == value) return true;
            }
            return false;
        }

        /// <summary>获取或设置下拉菜单的显示数量，最少显示 1 项。</summary>
        public int DropDownItems
        {
            get { return _combo.MaxDropDownItems; }
            set { _combo.MaxDropDownItems = (value > 0) ? value : 1; }
        }

        #endregion

        #region event

        /// <summary></summary>
        private void EventInit()
        {
            this.Resize += Event_Main_Resize;
            this.MouseMove += Event_Caption_MouseMove;
            this.MouseLeave += Event_Caption_MouseLeave;
            this.MouseDown += Event_Caption_MouseDown;

            _left.MouseMove += Event_Caption_MouseMove;
            _left.MouseLeave += Event_Caption_MouseLeave;
            _left.MouseDown += Event_Caption_MouseDown;

            _right.MouseMove += Event_Caption_MouseMove;
            _right.MouseLeave += Event_Caption_MouseLeave;
            _right.MouseDown += Event_Caption_MouseDown;

            _label.MouseMove += Event_Caption_MouseMove;
            _label.MouseLeave += Event_Caption_MouseLeave;
            _label.MouseDown += Event_Caption_MouseDown;

            _input.MouseMove += Event_Caption_MouseMove;
            _input.MouseLeave += Event_Caption_MouseLeave;
            _input.GotFocus += Event_GotFocus;
            _input.LostFocus += Event_LostFocus;
            _input.TextChanged += Event_Input_TextChanged;
            _input.KeyDown += (s, e) => OnKeyDown(e);
            _input.KeyUp += (s, e) => OnKeyUp(e);
            _input.KeyPress += (s, e) => OnKeyPress(e);

            _combo.DrawItem += Event_Combo_DrawItem;
            _combo.SelectedIndexChanged += Event_Combo_SelectedIndexChanged;
            _combo.MouseMove += Event_Caption_MouseMove;
            _combo.MouseLeave += Event_Caption_MouseLeave;
        }

        /// <summary></summary>
        private void Event_Input_TextChanged(object sender, EventArgs e)
        {
            // 抛出事件
            if ((Changed != null) && (!Locked)) Changed(this, new EventArgs());
        }

        /// <summary></summary>
        private void Event_Radio_MouseDown(object sender, MouseEventArgs e)
        {
            if (Locked) return;
            Text = ((BlockButton)sender).Tag.ToString();
            //updatemode();
        }

        /// <summary></summary>
        private void Event_Combo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Locked) return;
            if (_combo.SelectedIndex < 0) return;
            if (_combo.SelectedIndex >= _combo.Items.Count) return;

            var vold = string.IsNullOrEmpty(_text) ? "" : _text;
            var vnew = string.IsNullOrEmpty(_value[_combo.SelectedIndex]) ? "" : _value[_combo.SelectedIndex];
            var vchanged = (vold != vnew);
            _text = vnew;
            if (vchanged && (Changed != null)) Changed(this, new EventArgs());
        }

        /// <summary></summary>
        private void Event_Combo_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;
            e.DrawBackground();
            e.DrawFocusRectangle();
            var vs = _combo.Items[e.Index].ToString();
            var vx = e.Bounds.X + 7;
            var vy = e.Bounds.Y + (_combo.ItemHeight - 16) / 2;
            var vb = new SolidBrush(e.ForeColor);
            if (_color != null)
            {
                if (e.Index < _color.Count)
                {
                    vb.Dispose();
                    vb = new SolidBrush(_color[e.Index]);
                }
            }
            e.Graphics.DrawString(vs, FormsUtility.DefaultFont, vb, vx, vy);
            vb.Dispose();
        }

        /// <summary></summary>
        private void Event_LostFocus(object sender, EventArgs e)
        {
            _statefocus = false; GoColor();
        }

        /// <summary></summary>
        private void Event_GotFocus(object sender, EventArgs e)
        {
            _statefocus = true; GoColor();
        }

        /// <summary></summary>
        private void Event_Caption_MouseDown(object sender, MouseEventArgs e)
        {
            _input.Focus();
        }

        /// <summary></summary>
        private void Event_Main_Resize(object sender, EventArgs e)
        {
            ControlAdjust();
        }

        /// <summary></summary>
        private void Event_Caption_MouseLeave(object sender, EventArgs e)
        {
            _statehover = false; GoColor();
        }

        /// <summary></summary>
        private void Event_Caption_MouseMove(object sender, MouseEventArgs e)
        {
            _statehover = true; GoColor();
        }

        #endregion

        #region property

        /// <summary>标签文本。</summary>
        public string Caption
        {
            get { return _label.Text; }
            set { _label.Text = string.IsNullOrEmpty(value) ? "" : value; }
        }

        /// <summary>内容文本。</summary>
        public new string Text
        {
            get
            {
                switch (_mode)
                {
                    case modeinput: return _input.Text;
                    default: return _text;
                }
            }
            set
            {
                switch (_mode)
                {
                    case modeinput:
                        _input.Text = string.IsNullOrEmpty(value) ? "" : value;
                        break;
                    default:
                        var vchanged = (_text != value);
                        _text = string.IsNullOrEmpty(value) ? "" : value;
                        if (vchanged && (Changed != null)) Changed(this, new EventArgs());
                        break;
                }

                // 更新下拉菜单。
                if (_mode == modecombo)
                {
                    //var vexist = false;
                    for (int i = 0; i < _value.Count; i++)
                    {
                        if (_value[i] == Text)
                        {
                            //vexist = true;
                            _combo.SelectedIndex = i;
                        }
                    }
                    //if (!vexist)
                    //{
                    //    add(_input.Text, _input.Text);
                    //    _combo.SelectedIndex = _combo.Items.Count - 1;
                    //}
                }

                // 更新单选按钮。
                if (_mode == moderadio)
                {
                    for (int i = 0; i < _radio.Count; i++)
                    {
                        if (_value[i] == Text) GoCurrent(_radio[i]);
                        else GoCandidate(_radio[i]);
                    }
                }
            }
        }

        /// <summary>内容文本最大长度。</summary>
        public int Capacity
        {
            get { return _input.MaxLength; }
            set { _input.MaxLength = (value < 0) ? 0 : value; }
        }

        /// <summary></summary>
        public float FontSize
        {
            get { return _input.Font.Size; }
            set { _input.Font = new Font(FormsUtility.DefaultFontName, value); }
        }

        /// <summary>以默认的密码字符显示。</summary>
        public bool Password
        {
            get { return _input.UseSystemPasswordChar; }
            set { _input.UseSystemPasswordChar = value; }
        }

        /// <summary>独立控件，不接受 Tab 键事件。</summary>
        public bool Lonely
        {
            get { return !_input.TabStop; } // return _lonely; }
            set { _input.TabStop = !value; } //            _lonely = value; _input.AcceptsTab = !value; }
        }

        /// <summary>锁定内容，禁止编辑。</summary>
        public override bool Locked
        {
            get { return _input.ReadOnly; }
            set
            {
                switch (_mode)
                {
                    case modeinput:
                        _input.ReadOnly = value;
                        break;
                    case moderadio:
                        foreach (var vi in _radio) vi.Locked = value;
                        break;
                    case modecombo:
                        _combo.Visible = !value;
                        break;
                }
                GoColor();
            }
        }

        /// <summary>内容为空。</summary>
        public bool IsEmpty
        {
            get { return string.IsNullOrEmpty(_input.Text); }
        }

        #endregion

        #region color

        private Color _normalborder = FormsUtility.GraceBorder;
        private Color _normalleft = FormsUtility.White;
        private Color _normalright = FormsUtility.White;
        private Color _normalcaption = FormsUtility.GraceLocked;
        private Color _normaltext = FormsUtility.Black;
        private Color _hoverborder = FormsUtility.GraceSilver;
        private Color _hoverleft = FormsUtility.White;
        private Color _hoverright = FormsUtility.White;
        private Color _hovercaption = FormsUtility.GraceLocked;
        private Color _hovertext = FormsUtility.Black;
        private Color _focusborder = FormsUtility.GraceSilver; //FormsUtility.silver;
        private Color _focusleft = FormsUtility.White; //FormsUtility.wall;
        private Color _focusright = FormsUtility.White;
        private Color _focuscaption = FormsUtility.GraceMinor;// FormsUtility.gray;
        private Color _focustext = FormsUtility.Black;

        /// <summary></summary>
        public Color NormalBorder { get { return _normalborder; } set { if (value != null) _normalborder = value; GoColor(); } }

        /// <summary></summary>
        public Color NormalLeft { get { return _normalleft; } set { if (value != null) _normalleft = value; GoColor(); } }

        /// <summary></summary>
        public Color NormalRight { get { return _normalright; } set { if (value != null) _normalright = value; GoColor(); } }

        /// <summary></summary>
        public Color NormalCaption { get { return _normalcaption; } set { if (value != null) _normalcaption = value; GoColor(); } }

        /// <summary></summary>
        public Color NormalText { get { return _normaltext; } set { if (value != null) _normaltext = value; GoColor(); } }

        /// <summary></summary>
        public Color HoverBorder { get { return _hoverborder; } set { if (value != null) _hoverborder = value; GoColor(); } }

        /// <summary></summary>
        public Color HoverLeft { get { return _hoverleft; } set { if (value != null) _hoverleft = value; GoColor(); } }

        /// <summary></summary>
        public Color HoverRight { get { return _hoverright; } set { if (value != null) _hoverright = value; GoColor(); } }

        /// <summary></summary>
        public Color HoverCaption { get { return _hovercaption; } set { if (value != null) _hovercaption = value; GoColor(); } }

        /// <summary></summary>
        public Color HoverText { get { return _hovertext; } set { if (value != null) _hovertext = value; GoColor(); } }

        /// <summary></summary>
        public Color FocusBorder { get { return _focusborder; } set { if (value != null) _focusborder = value; GoColor(); } }

        /// <summary></summary>
        public Color FocusLeft { get { return _focusleft; } set { if (value != null) _focusleft = value; GoColor(); } }

        /// <summary></summary>
        public Color FocusRight { get { return _focusright; } set { if (value != null) _focusright = value; GoColor(); } }

        /// <summary></summary>
        public Color FocusCaption { get { return _focuscaption; } set { if (value != null) _focuscaption = value; GoColor(); } }

        /// <summary></summary>
        public Color FocusText { get { return _focustext; } set { if (value != null) _focustext = value; GoColor(); } }

        #endregion

        //protected override void OnEnabledChanged(EventArgs e)
        //{
        //    if (Enabled == false)
        //    {
        //        SetStyle(ControlStyles.UserPaint, true);
        //    }
        //    else
        //    {
        //        SetStyle(ControlStyles.UserPaint, false);
        //    }
        //    base.OnEnabledChanged(e);
        //}

        //protected override void OnPaint(PaintEventArgs pe)
        //{
        //    base.OnPaint(pe);
        //    if (Enabled == false)
        //    {
        //        pe.Graphics.FillRectangle(new SolidBrush(SystemColors.ControlLight),
        //        pe.ClipRectangle);
        //        int x = 0, y = 0;
        //        Size s = pe.Graphics.MeasureString(Text, Font).ToSize();
        //        x = Width - s.Width;
        //        y = (Height - s.Height) / 2;
        //        pe.Graphics.DrawString(this.Text, this.Font, Brushes.Black, x, y);
        //    }

        //}

    }
}

#endif
